﻿using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Reflection;
using YK.Core.Commons.Tools;

namespace YK.Core.Commons;

public static class Reflections
{
    /// <summary>
    /// 获取类型
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    public static Type GetType<T>()
    {
        return GetType(typeof(T));
    }

    /// <summary>
    /// 获取类型
    /// </summary>
    /// <param name="type">类型</param>
    public static Type GetType(Type type)
    {
        return Nullable.GetUnderlyingType(type) ?? type;
    }

    /// <summary>
    /// 获取程序集集合
    /// </summary>
    /// <param name="assemblyNames"></param>
    /// <returns></returns>
    public static Assembly[] GetAssemblyList(string[]? assemblyNames)
    {
        List<Assembly> assemblies = new();

        if (!(assemblyNames?.Length > 0))
        {
            return assemblies.ToArray();
        }

        foreach (var assemblyName in assemblyNames)
        {
            var assembly = Assembly.Load(assemblyName);
            if (assembly != null)
            {
                assemblies.Add(assembly);
            }
        }

        return assemblies.ToArray();
    }

    /// <summary>
    /// 获取程序集中指定接口的所有实现类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="assemblyNames"></param>
    /// <returns></returns>
    public static IEnumerable<Type> GetImplementations<T>(string[]? assemblyNames)
    {
        return GetImplementations<T>(GetAssemblyList(assemblyNames));
    }

    /// <summary>
    /// 获取程序集中指定接口的所有实现类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="assemblies"></param>
    /// <returns></returns>
    public static IEnumerable<Type> GetImplementations<T>(Assembly[] assemblies)
    {
        var interfaceType = typeof(T);
        var impTypes = assemblies
                   .SelectMany(s => s.GetExportedTypes())
                   .Where(t => interfaceType.IsAssignableFrom(t)
                               && t.IsClass && !t.IsAbstract)
                   .Select(t => t)
                   .ToList();
        return impTypes;
    }


    public static TAttribute GetSingleAttributeOrDefaultByFullSearch<TAttribute>(TypeInfo info)
        where TAttribute : Attribute
    {
        var attributeType = typeof(TAttribute);
        if (info.IsDefined(attributeType, true))
        {
            return info.GetCustomAttributes(attributeType, true).Cast<TAttribute>().First();
        }
        else
        {
            foreach (var implInter in info.ImplementedInterfaces)
            {
                var res = GetSingleAttributeOrDefaultByFullSearch<TAttribute>(implInter.GetTypeInfo());

                if (res != null)
                {
                    return res;
                }
            }
        }

        return null;
    }

    public static TAttribute GetSingleAttributeOrDefault<TAttribute>(MemberInfo memberInfo, TAttribute defaultValue = default(TAttribute), bool inherit = true)
        where TAttribute : Attribute
    {
        var attributeType = typeof(TAttribute);
        if (memberInfo.IsDefined(typeof(TAttribute), inherit))
        {
            return memberInfo.GetCustomAttributes(attributeType, inherit).Cast<TAttribute>().First();
        }

        return defaultValue;
    }

    /// <summary>
    /// 获取类型描述，使用DescriptionAttribute设置描述
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    public static string GetDescription<T>()
    {
        return GetDescription(GetType<T>());
    }

    /// <summary>
    /// 获取类型成员描述，使用DescriptionAttribute设置描述
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    /// <param name="memberName">成员名称</param>
    public static string GetDescription<T>(string memberName)
    {
        return GetDescription(GetType<T>(), memberName);
    }

    /// <summary>
    /// 获取类型成员描述，使用DescriptionAttribute设置描述
    /// </summary>
    /// <param name="type">类型</param>
    /// <param name="memberName">成员名称</param>
    public static string GetDescription(Type type, string memberName)
    {
        if (type == null)
            return string.Empty;
        if (string.IsNullOrWhiteSpace(memberName))
            return string.Empty;
        return GetDescription(type.GetTypeInfo().GetMember(memberName).FirstOrDefault());
    }

    /// <summary>
    /// 获取类型成员描述，使用DescriptionAttribute设置描述
    /// </summary>
    /// <param name="member">成员</param>
    public static string GetDescription(MemberInfo member)
    {
        if (member == null)
            return string.Empty;
        return member.GetCustomAttribute<DescriptionAttribute>() is DescriptionAttribute attribute ? attribute.Description : member.Name;
    }

    /// <summary>
    /// 获取类型描述
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public static string GetDescription(Type? type)
    {
        var desc = type?.GetCustomAttribute<DescriptionAttribute>(false);
        return desc?.Description ?? string.Empty;
    }

    /// <summary>
    /// 获取显示名称，使用DisplayNameAttribute设置显示名称
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    public static string GetDisplayName<T>()
    {
        return GetDisplayName(GetType<T>());
    }

    /// <summary>
    /// 获取显示名称，使用DisplayAttribute或DisplayNameAttribute设置显示名称
    /// </summary>
    public static string GetDisplayName(MemberInfo member)
    {
        if (member == null)
            return string.Empty;
        if (member.GetCustomAttribute<DisplayAttribute>() is DisplayAttribute displayAttribute)
            return displayAttribute.Name ?? "";
        if (member.GetCustomAttribute<DisplayNameAttribute>() is DisplayNameAttribute displayNameAttribute)
            return displayNameAttribute.DisplayName;
        return string.Empty;
    }

    /// <summary>
    /// 获取显示名称或描述,使用DisplayNameAttribute设置显示名称,使用DescriptionAttribute设置描述
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    public static string GetDisplayNameOrDescription<T>()
    {
        return GetDisplayNameOrDescription(GetType<T>());
    }

    /// <summary>
    /// 获取属性显示名称或描述,使用DisplayAttribute或DisplayNameAttribute设置显示名称,使用DescriptionAttribute设置描述
    /// </summary>
    public static string GetDisplayNameOrDescription(MemberInfo member)
    {
        var result = GetDisplayName(member);
        return string.IsNullOrWhiteSpace(result) ? GetDescription(member) : result;
    }

    /// <summary>
    /// 查找类型列表
    /// </summary>
    /// <typeparam name="TFind">查找类型</typeparam>
    /// <param name="assemblies">待查找的程序集列表</param>
    public static List<Type> FindTypes<TFind>(params Assembly[] assemblies)
    {
        var findType = typeof(TFind);
        return FindTypes(findType, assemblies);
    }

    /// <summary>
    /// 查找类型列表
    /// </summary>
    /// <param name="findType">查找类型</param>
    /// <param name="assemblies">待查找的程序集列表</param>
    public static List<Type> FindTypes(Type findType, params Assembly[] assemblies)
    {
        var result = new List<Type>();
        foreach (var assembly in assemblies)
            result.AddRange(GetTypes(findType, assembly));
        return result.Distinct().ToList();
    }

    /// <summary>
    /// 获取类型列表
    /// </summary>
    private static List<Type> GetTypes(Type findType, Assembly assembly)
    {
        var result = new List<Type>();
        if (assembly == null)
            return result;
        Type[] types;
        try
        {
            types = assembly.GetTypes();
        }
        catch (ReflectionTypeLoadException)
        {
            return result;
        }
        foreach (var type in types)
            AddType(result, findType, type);
        return result;
    }

    /// <summary>
    /// 添加类型
    /// </summary>
    private static void AddType(List<Type> result, Type findType, Type type)
    {
        if (type.IsInterface || type.IsAbstract)
            return;
        if (findType.IsAssignableFrom(type) == false && MatchGeneric(findType, type) == false)
            return;
        result.Add(type);
    }

    /// <summary>
    /// 泛型匹配
    /// </summary>
    private static bool MatchGeneric(Type findType, Type type)
    {
        if (findType.IsGenericTypeDefinition == false)
            return false;
        var definition = findType.GetGenericTypeDefinition();
        foreach (var implementedInterface in type.FindInterfaces((filter, criteria) => true, null))
        {
            if (implementedInterface.IsGenericType == false)
                continue;
            return definition.IsAssignableFrom(implementedInterface.GetGenericTypeDefinition());
        }
        return false;
    }

    /// <summary>
    /// 获取实现了接口的所有实例
    /// </summary>
    /// <typeparam name="TInterface">接口类型</typeparam>
    /// <param name="assemblies">待查找的程序集列表</param>
    public static List<TInterface?> GetInstancesByInterface<TInterface>(params Assembly[] assemblies)
    {
        return FindTypes<TInterface>(assemblies)
            .Select(t => CreateInstance<TInterface>(t)).ToList();
    }

    /// <summary>
    /// 动态创建实例
    /// </summary>
    /// <typeparam name="T">目标类型</typeparam>
    /// <param name="type">类型</param>
    /// <param name="parameters">传递给构造函数的参数</param>        
    public static T? CreateInstance<T>(Type type, params object[] parameters)
    {
        return Converts.To<T>(Activator.CreateInstance(type, parameters));
    }

    /// <summary>
    /// 获取程序集
    /// </summary>
    /// <param name="assemblyName">程序集名称</param>
    public static Assembly GetAssembly(string assemblyName)
    {
        return Assembly.Load(new AssemblyName(assemblyName));
    }

    /// <summary>
    /// 是否布尔类型
    /// </summary>
    /// <param name="member">成员</param>
    public static bool IsBool(MemberInfo member)
    {
        if (member == null)
            return false;
        switch (member.MemberType)
        {
            case MemberTypes.TypeInfo:
                return member.ToString() == "System.Boolean";
            case MemberTypes.Property:
                return IsBool((PropertyInfo)member);
        }
        return false;
    }

    /// <summary>
    /// 是否布尔类型
    /// </summary>
    private static bool IsBool(PropertyInfo property)
    {
        return property.PropertyType == typeof(bool) || property.PropertyType == typeof(bool?);
    }

    /// <summary>
    /// 是否枚举类型
    /// </summary>
    /// <param name="member">成员</param>
    public static bool IsEnum(MemberInfo member)
    {
        if (member == null)
            return false;
        switch (member.MemberType)
        {
            case MemberTypes.TypeInfo:
                return ((TypeInfo)member).IsEnum;
            case MemberTypes.Property:
                return IsEnum((PropertyInfo)member);
        }
        return false;
    }

    /// <summary>
    /// 是否枚举类型
    /// </summary>
    private static bool IsEnum(PropertyInfo property)
    {
        if (property.PropertyType.GetTypeInfo().IsEnum)
            return true;
        var value = Nullable.GetUnderlyingType(property.PropertyType);
        if (value == null)
            return false;
        return value.GetTypeInfo().IsEnum;
    }

    /// <summary>
    /// 是否日期类型
    /// </summary>
    /// <param name="member">成员</param>
    public static bool IsDate(MemberInfo member)
    {
        if (member == null)
            return false;
        switch (member.MemberType)
        {
            case MemberTypes.TypeInfo:
                return member.ToString() == "System.DateTime";
            case MemberTypes.Property:
                return IsDate((PropertyInfo)member);
        }
        return false;
    }

    /// <summary>
    /// 是否日期类型
    /// </summary>
    private static bool IsDate(PropertyInfo property)
    {
        if (property.PropertyType == typeof(DateTime))
            return true;
        if (property.PropertyType == typeof(DateTime?))
            return true;
        return false;
    }

    /// <summary>
    /// 是否整型
    /// </summary>
    /// <param name="member">成员</param>
    public static bool IsInt(MemberInfo member)
    {
        if (member == null)
            return false;
        switch (member.MemberType)
        {
            case MemberTypes.TypeInfo:
                return member.ToString() == "System.Int32" || member.ToString() == "System.Int16" || member.ToString() == "System.Int64";
            case MemberTypes.Property:
                return IsInt((PropertyInfo)member);
        }
        return false;
    }

    /// <summary>
    /// 是否整型
    /// </summary>
    private static bool IsInt(PropertyInfo property)
    {
        if (property.PropertyType == typeof(int))
            return true;
        if (property.PropertyType == typeof(int?))
            return true;
        if (property.PropertyType == typeof(short))
            return true;
        if (property.PropertyType == typeof(short?))
            return true;
        if (property.PropertyType == typeof(long))
            return true;
        if (property.PropertyType == typeof(long?))
            return true;
        return false;
    }

    /// <summary>
    /// 是否数值类型
    /// </summary>
    /// <param name="member">成员</param>
    public static bool IsNumber(MemberInfo member)
    {
        if (member == null)
            return false;
        if (IsInt(member))
            return true;
        switch (member.MemberType)
        {
            case MemberTypes.TypeInfo:
                return member.ToString() == "System.Double" || member.ToString() == "System.Decimal" || member.ToString() == "System.Single";
            case MemberTypes.Property:
                return IsNumber((PropertyInfo)member);
        }
        return false;
    }

    /// <summary>
    /// 是否数值类型
    /// </summary>
    private static bool IsNumber(PropertyInfo property)
    {
        if (property.PropertyType == typeof(double))
            return true;
        if (property.PropertyType == typeof(double?))
            return true;
        if (property.PropertyType == typeof(decimal))
            return true;
        if (property.PropertyType == typeof(decimal?))
            return true;
        if (property.PropertyType == typeof(float))
            return true;
        if (property.PropertyType == typeof(float?))
            return true;
        return false;
    }

    /// <summary>
    /// 是否集合
    /// </summary>
    /// <param name="type">类型</param>
    public static bool IsCollection(Type type)
    {
        if (type.IsArray)
            return true;
        return IsGenericCollection(type);
    }

    /// <summary>
    /// 是否泛型集合
    /// </summary>
    /// <param name="type">类型</param>
    public static bool IsGenericCollection(Type type)
    {
        if (!type.IsGenericType)
            return false;
        var typeDefinition = type.GetGenericTypeDefinition();
        return typeDefinition == typeof(IEnumerable<>)
               || typeDefinition == typeof(IReadOnlyCollection<>)
               || typeDefinition == typeof(IReadOnlyList<>)
               || typeDefinition == typeof(ICollection<>)
               || typeDefinition == typeof(IList<>)
               || typeDefinition == typeof(List<>);
    }

    /// <summary>
    /// 从目录中获取所有程序集
    /// </summary>
    /// <param name="directoryPath">目录绝对路径</param>
    public static List<Assembly> GetAssemblies(string directoryPath)
    {
        return Directory.GetFiles(directoryPath, "*.*", SearchOption.AllDirectories).ToList()
            .Where(t => t.EndsWith(".exe") || t.EndsWith(".dll"))
            .Select(path => Assembly.Load(new AssemblyName(path))).ToList();
    }

    /// <summary>
    /// 获取顶级基类
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    public static Type GetTopBaseType<T>()
    {
        return GetTopBaseType(typeof(T));
    }

    /// <summary>
    /// 获取顶级基类
    /// </summary>
    /// <param name="type">类型</param>
    public static Type GetTopBaseType(Type type)
    {
        if (type == null)
            return null;
        if (type.IsInterface)
            return type;
        if (type.BaseType == typeof(object))
            return type;
        return GetTopBaseType(type.BaseType);
    }
}
